package io.github.iogogogo.commons.util;

import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by tao.zeng on 2024/11/7.
 */
public class TreeUtils {

    /**
     * # 分隔符
     */
    public final static Splitter SPLITTER_00100011 = Splitter.on("#");
    /**
     * / 分隔符
     */
    public final static Splitter SPLITTER_00101111 = Splitter.on("/");

    /**
     * 递归分组
     *
     * @param list      原数据集合
     * @param index     递归索引
     * @param groupKeys 分组的key集合，组合key用#拼接 Lists.newArrayList("key1#key2", "key3", "key4#key5#key6")
     * @param parentId  递归parentId
     * @return tree集合
     */
    public static List<PartitionTree> groupingBy(List<Map<String, Object>> list, int index, List<String> groupKeys, Serializable parentId) {
        if (index >= groupKeys.size()) return Collections.emptyList();

        LocalDateTime now = DateTimeUtils.nowDateTime();
        String groupKey = groupKeys.get(index);
        Iterable<String> keys = SPLITTER_00100011.split(groupKey);

        Map<String, List<Map<String, Object>>> map = list.stream().collect(Collectors.groupingBy(v -> {
            List<String> values = new ArrayList<>();
            for (String key : keys) {
                values.add(String.valueOf(v.getOrDefault(key, "")));
            }
            // 如 key1#key2 则组合分组
            return StringUtils.join(values, "#");
        }));
        index++;
        int i = index;
        List<PartitionTree> treeList = Lists.newArrayList();
        map.forEach((k, v) -> {
            PartitionTree tree = new PartitionTree();
            String id = IdHelper.uuid();
            tree.setId(id);
            tree.setGroupKey(groupKey);
            tree.setValue(k);
            tree.setParentId(parentId);
            tree.setCount(v.size());
            tree.setTimestamp(now);
            tree.setChildren(groupingBy(v, i, groupKeys, id));
            treeList.add(tree);
        });
        return treeList;
    }

    public static class TreeModel {
        private final List<Tree> menuList;

        public TreeModel(List<Tree> menuList) {
            this.menuList = menuList;
            // 按照sort升序排序
            menuList.sort(Comparator.comparing(Tree::getSort));
        }

        /**
         * 建立树形结构
         *
         * @return 树形结构
         */
        public List<Tree> buildTree() {
            // 获取根节点
            List<Tree> rootNode = menuList.stream().filter(x -> "0".equals(x.getParentId())).collect(Collectors.toList());
            return rootNode.stream().map(this::buildTreeByStream).collect(Collectors.toList());
        }

        /**
         * 递归，建立子树形结构
         *
         * @param parentNode 父节点
         * @return 树形结构
         */
        private Tree buildTreeByForeach(Tree parentNode) {
            List<Tree> childrenMenus = Lists.newArrayList();
            for (Tree menuNode : menuList) {
                if (menuNode.getParentId().equals(parentNode.getId())) {
                    childrenMenus.add(buildTreeByForeach(menuNode));
                }
            }
            parentNode.setChildren(childrenMenus);
            return parentNode;
        }

        /**
         * 递归，建立子树形结构
         *
         * @param parentNode 父节点
         * @return 树形结构
         */
        private Tree buildTreeByStream(Tree parentNode) {
            List<Tree> childrenMenus = menuList.stream()
                    .filter(x -> x.getParentId().equals(parentNode.getId()))
                    .map(this::buildTreeByStream)
                    .collect(Collectors.toList());
            parentNode.setChildren(childrenMenus);
            return parentNode;
        }
    }

    @Data
    public static class Tree {
        private String id;
        private String parentId;
        private String text;
        private String url;
        private List<Tree> children;
        private Integer sort;
    }

    @Data
    public static class PartitionTree implements Serializable {
        private Serializable id;
        private String groupKey;
        private String value;
        private Serializable parentId;
        private Integer count;
        private LocalDateTime timestamp;
        private List<PartitionTree> children;
    }
}
